package com.tong.hao.common.mybatis.generate;

import cn.buddha.jec.util.TongUtils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.tong.hao.common.mybatis.config.ThDataSourceConfig;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName MysqlGenerator
 * @Author 友野浩二
 * @Description mybatis-plus代码生成器
 * @Version 1.0
 */
@Slf4j
public class MysqlGenerator {

    private static final String AUTHOR = "彤彤";
    private static final String OUTPUT_DIR = "/hao-common/src/test/java";// java文件路径
    private static final String PACKAGE_PARENT = "com.tong.hao.common.baomidou";// java文件包路径的父目录
    private static final String MAPPER_DIR = "/hao-common/src/test/resources/mapper/";// mapper文件路径
    private static final String TEMPLATE_PATH = "/templates/mapper.xml.vm";// mapper文件模板

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        String projectPath = System.getProperty("user.dir");

        // ======== 1- 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setAuthor(AUTHOR);// 开发人员
        gc.setOutputDir(projectPath.concat(OUTPUT_DIR));// 生成文件的输出目录
        gc.setFileOverride(true);// 是否覆盖已有文件
        /*
         * ActiveRecord的模式:
         *      实体类只需继承 Model 类即可实现基本 CRUD 操作.
         *      简单来说就是一个实体类继承Model类，并通过注解与数据库的表名进行关联，这样就可以通过实体类直接进行表的简单增删改查操作
         * 其实和mybatis-plus本身的mapper接口实现的BaseMapper类似的。
         */
        gc.setActiveRecord(false);// 默认即为false
        gc.setOpen(true);// 是否打开输出目录,默认即为true
        mpg.setGlobalConfig(gc);

        // ======== 2- 数据源配置,指定需要生成代码的具体数据库
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);// 数据库类型: MySQL
        dsc.setUrl(ThDataSourceConfig.DB_URL.getJdbcConf());
        dsc.setUsername(ThDataSourceConfig.DB_USER_NAME.getJdbcConf());
        dsc.setPassword(ThDataSourceConfig.DB_PASSWORD.getJdbcConf());
        dsc.setDriverName(ThDataSourceConfig.DB_DRIVER_NAME.getJdbcConf());
        // 类型转换
        dsc.setTypeConvert(new MySqlTypeConvert() {
            // 自定义数据库表字段类型转换【可选】
            @Override
            public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
                globalConfig = gc;
                log.info("MySQL表字段转换类型: {}", fieldType);
                // 【注意】：processTypeConvert存在默认类型转换,如果不是欧巴想要的效果就需要自定义返回类型
                return super.processTypeConvert(globalConfig, fieldType);
            }
        });
        mpg.setDataSource(dsc);

        // ======== 3- 包配置,指定生成代码的包路径
        PackageConfig pc = new PackageConfig();
        pc.setParent(PACKAGE_PARENT);// 父包名
        pc.setModuleName(TongUtils.scanner("模块名"));// 父包模块名
        mpg.setPackageInfo(pc);

        // ======== 4- 策略配置
        StrategyConfig sc = new StrategyConfig();
        sc.setNaming(NamingStrategy.underline_to_camel);// 数据库表映射到实体的命名策略: 下划线转驼峰命名
        sc.setColumnNaming(NamingStrategy.underline_to_camel);// 数据库表字段映射到实体的命名策略: 下划线转驼峰命名
//        sc.setTablePrefix(pc.getModuleName().concat("_"));// 表前缀: 按模块区分
        sc.setInclude(TongUtils.scanner("表名[多个表名英文逗号,分隔]").split(","));// 需要包含的表名，允许正则表达式
        sc.setEntityLombokModel(true);// 【实体】是否为lombok模型
        sc.setEntityTableFieldAnnotationEnable(true);// 是否生成实体时，生成字段注解
        sc.setRestControllerStyle(true);// 生成 <code>@RestController</code> 控制器
        mpg.setStrategy(sc);

        // 5- 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);// 关闭xml的默认生成路径+文件名,然后在 "6- 注入自定义配置" 中调整xml文件路径
        mpg.setTemplate(templateConfig);

        // 6- 注入自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        // 自定义输出配置(优先输出)
        List<FileOutConfig> focList = new ArrayList<>();
        // 调整 XML 的生成目录
        focList.add(new FileOutConfig(TEMPLATE_PATH) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名，如果 entity 设置了前后缀，此处xml的名称会跟着变化
                // 工程路径 + "/src/test/resources/mapper" + 模块名 + "/" + entityName + "Mapper.xml"
                return projectPath.concat(MAPPER_DIR).concat(pc.getModuleName()).concat(StringPool.SLASH).
                        concat(tableInfo.getEntityName()).concat("Mapper").concat(StringPool.DOT_XML);
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 执行生成
        mpg.execute();
    }

}
